package com.lsf.modules.system.controller;

import cn.hutool.core.lang.RegexPool;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lsf.common.api.CommonApi;
import com.lsf.common.api.vo.Result;
import com.lsf.common.constant.CacheConstant;
import com.lsf.common.constant.CommonConstant;
import com.lsf.modules.base.service.BaseCommonService;
import com.lsf.modules.base.vo.LoginUser;
import com.lsf.modules.system.entity.User;
import com.lsf.modules.system.handle.EmailSendMsgHandle;
import com.lsf.modules.system.model.LoginModel;
import com.lsf.modules.system.model.RegisterModel;
import com.lsf.modules.system.service.UserService;
import com.lsf.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * @author Alexander
 */
@RestController
@RequestMapping("/sys")
@Slf4j
public class LoginController {
    @Resource
    private UserService userService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private BaseCommonService baseCommonService;
    @Resource
    private CommonApi commonApi;

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";

    @PostMapping("/register")
    public Result<JSONObject> register(@RequestBody @Validated RegisterModel registerModel) {
        Result<JSONObject> result = new Result<>();
        String username = registerModel.getUsername();
        String regName = "^(?![0-9]+$)[a-zA-Z0-9\\u4e00-\\u9fa5]{4,20}$";
        if (!username.matches(regName)) {
            result.setMessage("用户名不符合要求");
            result.setSuccess(false);
            return result;
        }
        String password = registerModel.getPassword();
        String regPassword = "^(?![a-zA-Z]+$)(?![0-9]+$)[0-9a-zA-Z@_]{6,20}$";
        if (!password.matches(regPassword)) {
            result.setMessage("密码不符合要求");
            result.setSuccess(false);
            return result;
        }
        String email = registerModel.getEmail();
        String regEmail = RegexPool.EMAIL;
        if (!email.matches(regEmail)) {
            result.setMessage("email不符合要求");
            result.setSuccess(false);
            return result;
        }
        String phone = registerModel.getPhone();
        String regPhone = RegexPool.MOBILE;
        if (!phone.matches(regPhone)) {
            result.setMessage("手机号不符合要求");
            result.setSuccess(false);
            return result;
        }
        User user1 = userService.getUserByName(username);
        if (user1 != null) {
            result.setMessage("用户名已注册");
            result.setSuccess(false);
            return result;
        }
        User user2 = userService.getUserByPhone(phone);
        if (user2 != null) {
            result.setMessage("手机号已注册");
            result.setSuccess(false);
            return result;
        }
        User user3 = userService.getUserByEmail(email);
        if (user3 != null) {
            result.setMessage("邮箱已注册");
            result.setSuccess(false);
            return result;
        }
        Object code = redisUtil.get(email);
        if (code == null) {
            result.setMessage("邮箱证码失效,请重新获取");
            result.setSuccess(false);
            return result;
        }
        String smsCode = registerModel.getSmsCode();
        if (!smsCode.equals(code.toString())) {
            result.setMessage("邮箱验证码错误");
            result.setSuccess(false);
            return result;
        }
        Integer sex = registerModel.getSex();
        try {
            User user = new User();
            user.setUsername(username);
            String salt = RandomUtil.randomString(BASE_CHECK_CODES, 8);
            String passwordEncode = PasswordUtil.encrypt(username, password, salt);
            user.setPassword(passwordEncode);
            user.setSalt(salt);
            user.setEmail(email);
            user.setPhone(phone);
            user.setSex(sex);
            user.setStatus(CommonConstant.USER_UNFREEZE);
            user.setDelFlag(CommonConstant.DEL_FLAG_0);
            user.setCreateTime(new Date());
            userService.addUserWithRole(user, "1459885591166550018");
            result.success("注册成功");
        } catch (Exception e) {
            result.error500("注册失败");
            log.error(e.getMessage(), e);
        }
        return result;
    }

    /**
     * 登录
     *
     * @return {@link Result}<{@link JSONObject}>
     */
    @PostMapping("/login")
    public Result<JSONObject> login(@RequestBody @Validated LoginModel loginModel) {
        Result<JSONObject> result = new Result<>();
        String username = loginModel.getUsername();
        String password = loginModel.getPassword();
        //校验验证码
        String captcha = loginModel.getCaptcha();
        if (captcha == null) {
            result.error500("验证码无效");
            return result;
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5.create().digestHex16(lowerCaseCaptcha + loginModel.getCheckKey(), StandardCharsets.UTF_8);
        Object checkCode = redisUtil.get(realKey);
        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            result.error500("验证码错误");
            return result;
        }
        //校验用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        User user = userService.getOne(queryWrapper);
        result = userService.checkUserIsEffective(user);
        if (!result.isSuccess()) {
            return result;
        }
        String inputPassword = PasswordUtil.encrypt(username, password, user.getSalt());
        String sysPassword = user.getPassword();
        if (!sysPassword.equals(inputPassword)) {
            result.error500("用户名或密码错误");
            return result;
        }
        //用户登录信息
        userInfo(user, result);
        baseCommonService.addLog("用户名：" + username + ",登陆成功!", CommonConstant.LOG_TYPE_1, null);
        return result;
    }

    /**
     * 用户信息
     *
     * @param user   用户
     * @param result 结果
     * @return {@link Result}<{@link JSONObject}>
     */
    private Result<JSONObject> userInfo(User user, Result<JSONObject> result) {
        String sysPassword = user.getPassword();
        String username = user.getUsername();
        JSONObject object = new JSONObject();
        String token = JwtUtil.sign(username, sysPassword);
        //设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
        object.put("token", token);
        object.put("userInfo", username);
        result.setResult(object);
        result.success("登陆成功");
        return result;
    }

    /**
     * 注销
     *
     * @param request 请求
     * @return {@link Result}
     */
    @GetMapping("/logout")
    public Result logout(HttpServletRequest request) {
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (StringUtils.isEmpty(token)) {
            return Result.error("退出登录失败!");
        }
        String username = JwtUtil.getUsername(token);
        LoginUser user = commonApi.getUserByName(username);
        if (user != null) {
            baseCommonService.addLog("用户名：" + user.getUsername() + ",退出成功!", CommonConstant.LOG_TYPE_1, null, user);
            log.info("用户名：" + username + "退出成功");
            //清空用户登录Token缓存
            redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
            //清空用户登录Shiro权限缓存
            redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + user.getId());
            //清空用户的缓存信息
            redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, username));
            //调用Shiro的logout
            SecurityUtils.getSubject().logout();
            return Result.OK("退出登录成功!");
        } else {
            return Result.error("Token无效!");
        }
    }

    /**
     * 后台生成图形验证码
     *
     * @param key
     * @return {@link Result}<{@link String}>
     */
    @GetMapping("/randomImage/{key}")
    public Result<String> randomImage(@PathVariable String key) {
        Result<String> result = new Result<>();
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5.create().digestHex16(lowerCaseCode + key, StandardCharsets.UTF_8);
            redisUtil.set(realKey, lowerCaseCode, 60);
            String base64 = RandImageUtil.generate(code);
            result.setSuccess(true);
            result.setResult(base64);
        } catch (Exception e) {
            result.error500("获取验证码错误" + e.getMessage());
            log.error(e.getMessage());
        }
        return result;
    }

    /**
     * 短信接口
     *
     * @return {@link Result}<{@link String}>
     */
    @PostMapping("/sms")
    public Result<String> sms(@RequestBody JSONObject jsonObject) {
        Result<String> result = new Result<>();
        String phone = jsonObject.get("phone").toString();
        //短信模板：0 .登录模板、1.注册模板、2.忘记密码模板
        String smsMode = jsonObject.get("smsMode").toString();
        if (StringUtils.isEmpty(phone)) {
            result.setMessage("手机号不能为空!");
            result.setSuccess(false);
            return result;
        }
        Object object = redisUtil.get(phone);
        if (object != null) {
            result.setMessage("验证码10分钟内,仍然有效!");
            result.setSuccess(false);
            return result;
        }
        //随机数生成验证码
        String captcha = RandomUtil.randomNumbers(6);
        JSONObject obj = new JSONObject();
        obj.put("code", captcha);
        try {
            boolean b = false;
            //注册模板
            User user = userService.getUserByPhone(phone);
            if (CommonConstant.SMS_TPL_TYPE_1.equals(smsMode)) {
                if (user != null) {
                    result.error500("手机号已经注册,请直接登录!");
                    baseCommonService.addLog("手机号已经注册,请直接登录!", CommonConstant.LOG_TYPE_1, null);
                    return result;
                }
                b = DySmsHelper.sendSms(phone, obj, DySmsEnum.REGISTER_TEMPLATE_CODE);
            } else {
                //登录模式,校验用户有效性
                result = userService.checkUserIsEffective(user);
                if (!result.isSuccess()) {
                    String message = result.getMessage();
                    if ("用户不存在,请注册".equals(message)) {
                        result.error500("用户不存在或未绑定手机号");
                    }
                    return result;
                }
                //smsmode 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
                if (CommonConstant.SMS_TPL_TYPE_0.equals(smsMode)) {
                    //登陆模板
                    b = DySmsHelper.sendSms(phone, obj, DySmsEnum.LOGIN_TEMPLATE_CODE);
                } else if (CommonConstant.SMS_TPL_TYPE_2.equals(smsMode)) {
                    //忘记密码模板
                    b = DySmsHelper.sendSms(phone, obj, DySmsEnum.FORGET_PASSWORD_TEMPLATE_CODE);
                }
            }
            if (b == false) {
                result.setMessage("短信验证码发送失败,请稍后重试");
                result.setSuccess(false);
                return result;
            }
            redisUtil.set(phone, captcha, 600);
            result.setSuccess(true);
        } catch (ClientException e) {
            log.error(e.getMessage(), e);
            result.error500("短信接口未配置,请联系管理员!");
            return result;
        }
        return result;
    }

    /**
     * 发送电子邮件
     *
     * @param receiver 接收人
     */
    @GetMapping("/sendEmail")
    public Result<JSONObject> sendEmail(@RequestParam("receiver") String receiver) {
        Result<JSONObject> result = new Result<>();
        if (StringUtils.isEmpty(receiver)) {
            result.setMessage("接收人不能为空");
            result.setSuccess(false);
            return result;
        }
        Object object = redisUtil.get(receiver);
        if (object != null) {
            result.setMessage("验证码60秒内,仍然有效!");
            result.setSuccess(false);
            return result;
        }
        try {
            //随机数生成验证码
            String captcha = RandomUtil.randomNumbers(6);
            log.info(captcha);
            redisUtil.set(receiver, captcha, 60);
            EmailSendMsgHandle.SendMsg(receiver, captcha);
            result.setSuccess(true);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("发送邮件失败," + e.getMessage());
        }
        return result;
    }


}
